using System;
using System.Collections.Generic;
using UnityEngine;

namespace LS.GameKit
{
    [RequireComponent(typeof(SpriteRenderer))]
    public class ComplexTiledSpriteController : MonoBehaviour
    {
        [SerializeField]
        private Vector2Int m_TiledSizeMaximum = new Vector2Int(16, 16);

        private SpriteRenderer m_Renderer;

        private Texture2D m_ColorMaskRT;

        private Material m_PreviousMaterial;
        private Material m_TempMaterial;
        private bool m_TextureChanged = false;

        public Sprite Sprite
        {
            get
            {
                return m_Renderer.sprite;
            }
            set
            {
                m_Renderer.sprite = value;
            }
        }

        public SpriteRenderer Renderer
        {
            get
            {
                return m_Renderer;
            }
        }

        public int TiledWidthMaximum
        {
            get
            {
                return m_TiledSizeMaximum.x;
            }
        }

        public int TiledHeightMaximum
        {
            get
            {
                return m_TiledSizeMaximum.y;
            }
        }

        private void Awake()
        {
            m_Renderer = GetComponent<SpriteRenderer>();
            ReinitializeColorMask(m_TiledSizeMaximum.x, m_TiledSizeMaximum.y);
        }

        private void OnEnable()
        {
            Shader shader = Shader.Find("Shader Graphs/ComplexTiledSpriteLit");
            if (m_Renderer.material.shader != shader)
            {
                m_PreviousMaterial = m_Renderer.material;

                if (m_TempMaterial == null)
                {
                    m_TempMaterial = new Material(shader);
                }

                m_Renderer.material = m_TempMaterial;
            }

            m_Renderer.material.SetTexture("_ColorMask", m_ColorMaskRT);

            ClearColor();
        }

        private void Update()
        {
            if (m_TextureChanged)
            {
                m_TextureChanged = false;
                m_ColorMaskRT?.Apply();
            }
        }

        private void OnDisable()
        {
            if (m_PreviousMaterial != null)
            {
                m_Renderer.material = m_PreviousMaterial;
                m_PreviousMaterial = null;
            }
        }

        public void ReinitializeColorMask(int width, int height)
        {
            m_TiledSizeMaximum = new Vector2Int(width, height);

            if (m_ColorMaskRT == null)
                m_ColorMaskRT = new Texture2D(TiledWidthMaximum, TiledHeightMaximum, TextureFormat.RGBA32, false);
            else
                m_ColorMaskRT.Reinitialize(width, height, TextureFormat.RGBA32, false);

            m_ColorMaskRT.filterMode = FilterMode.Point;
            m_TextureChanged = true;
        }

        public void SetColor(int x, int y, Color color)
        {
            if (x >= m_TiledSizeMaximum.x || y >= m_TiledSizeMaximum.y)
            {
                throw new IndexOutOfRangeException();
            }

            m_ColorMaskRT.SetPixel(x, y, color);
            m_TextureChanged = true;
        }

        public void ClearColor()
        {
            Color clean = new Color(1, 1, 1, 0);
            Color[] colors = new Color[m_TiledSizeMaximum.x * m_TiledSizeMaximum.y];
            for (int i = 0; i < colors.Length; i++)
            {
                colors[i] = clean;
            }
            m_ColorMaskRT.SetPixels(0, 0, m_TiledSizeMaximum.x, m_TiledSizeMaximum.y, colors);
            m_TextureChanged = true;
        }
    }
}
